home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MACD 5
/
MACD 5.bin
/
workbench
/
libs
/
usergrouplib.lha
/
usergroup
/
usergroup.c
< prev
Wrap
Text File
|
1992-09-02
|
23KB
|
736 lines
RCS_ID_C="$Id: usergroup.c,v 4.1 1994/05/16 14:09:07 ppessi Exp $";
/*
* Author: ppessi <Pekka.Pessi@hut.fi>
*
* This file is part of the AmiTCP/IP UserGroup Library.
*
* Copyright © 1993 AmiTCP/IP Group, <AmiTCP-Group@hut.fi>
* Helsinki University of Technology, Finland.
*
* Created : Sun Nov 28 17:45:55 1993 ppessi
* Last modified: Mon May 16 14:33:00 1994 ppessi
*
* $Log: usergroup.c,v $
* Revision 4.1 1994/05/16 14:09:07 ppessi
* Release 4
*
* Revision 3.1 1994/02/24 16:49:34 ppessi
* Release 3.
*
* Revision 2.2 1994/02/17 02:21:58 ppessi
* *** empty log message ***
*
* Revision 2.1 1994/01/23 03:23:23 ppessi
* Cleaned documentation. Added licence.
* Modified the errno pointer tags; there is now a separate tag
* for each legal errno size.
* Activated the UGT_OWNER code.
*
* Revision 1.3 1994/01/21 08:12:22 ppessi
* Added _ProgramName as first argument of ug_SetupContext()
*
* Revision 1.2 1994/01/20 08:28:13 ppessi
* Changed the ug_StrError slightly, an device error code is now also
* accepted.
*
* Revision 1.1 94/01/19 10:05:08 ppessi
* Initial revision
*
*/
/****** usergroup.library/--background-- ***********************************
WARNING
Unfortunately, this experimental release of usergroup.library is not
compatible with multiuser.library. There are some problems with
multiuser.library, eg. the multiuser.library does not support the
real ids. Also the password format is different, multiuser.library
uses the AS225r2 password format, which is very simple encoding.
The usergroup.library uses the standard Unix password encryption.
The current implementation of this model is very simple. All tasks
belong to one session and they share common credentials. The
setsid() function call does nothing. You are supposed to log in
using "login -f login-name" when the machine is booted.
PURPOSE
When the AmiTCP/IP was originally released, a little attention was
paid to the security aspects. Since the AmigaOS is basically a
single user operating system with little or no provisions for
multiple users, there was no standard how accounts, password
checking and access control should be implemented.
USERGROUP.LIBRARAY SEMANTICS
The usergroup.library provides a BSD-stylish interface to the user
and group identification, the account database, the group databases,
password checking and login information. Since it is a shared
library instead of link library, the underlying security mechanisms
can be changed according future standards and needs. The
usergroup.library provides quite clean basic model. Each process has
credentials, which consist of real used ID, real group ID, effective
user ID and up to 32 effective group IDs. The process credentials
can be changed with setuid()/setgid()/setgroups() functions.
Each process belongs also to an session. A new session will created
with setsid() function call, which is typically executed before you
call command or when you create a new connection. A session
contains the login name of the user and possibly some other
information.
The information about users logging in and out is typically stored
into a file in Unix systems. These files (in BSD Net2 release they
are /var/run/utmp and /var/log/wtmp) are usually very long and
contain holes. Since the AmigaDOS files cannot contain holes, this
approach is not practical. The usergroup.library provides an
loosely HP-UX-stylish interface to the utmp and lastlogin databases.
The utmp database contains an entry for each session, it is searched
in linear manner qith getutent(). The lastlogin database contains
an entry for each user and getlastlogin() returns an entry for given
UID.
The usergroup.library does not directly depend on AmiTCP/IP. It can
be used with any program needing user identification, account and
group databases.
USING USERGROUP.LIBRARY
Each time the usergroup.library is opened, it creates an new
instance of the library base. The library base contains the static
data buffers used by many library functions. The usergroup.library
functions behave exactly like they were in link library. The
functions allocate all resources for you, the library also frees the
resources when they are no more needed.
Since each library contains static data and resources allocated in
the context of calling task (ie. signals), only the task which
opened the library is allowed to call most library functions.
However, any task whatsoever can call following functions:
getuid() geteuid() getgid() getegid() getsid()
These functions return the credentials of calling task.
It is also possible to call following functions from any task.
However, note that a non-owning tasks cannot recover error codes:
getgroups() setreuid() setuid() setregid() setgid() setgroups()
setsid() setlogin()
It is possible to give the library instance to another task. Only
the current owner can close the library.
The user and group information is provided by netinfo.device.
It is more convenient interface to user and group databases
for multitasking applications.
EXAMPLE PROGRAMS
There are a few utilities provided as examples. The finger programs
deals with user (password), utmp and lastlog database, the id and
whoami with user and group identification, login and passwd with
password checking and password changing.
SEE ALSO
netinfo.device/--background--, ug_SetupContextTags(),
SAS C Manual, libinit.c and libinitr.o
COPYRIGHT
Copyright © 1980--1991 The Regents of the University of California.
Copyright © 1993, 1994 AmiTCP/IP-Group, <AmiTCP-Group@hut.fi>,
Helsinki University of Technology, Finland.
****************************************************************************
*/
/****** usergroup.library/--Licence-- **************************************
USERGROUP.LIBRARY LICENCE
The usergroup.library is Copyright © 1993, 1994 AmiTCP/IP-Group,
<AmiTCP-Group@hut.fi>, Helsinki University of Technology, Finland.
The usergroup.library contains source code from 4.3BSD Net2 release.
The 4.3BSD Net2 release is copyright © 1980 --- 1991 The Regents of
the University of California. The following licence apply to the
usergroup.library and its documentation:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. All advertising materials mentioning features or use of this
software must display the following acknowledgement: This product
includes software developed by the University of California,
Berkeley and its contributors.
4. Neither the name of the University nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
****************************************************************************
*/
#include "base.h"
#include "libfunc.h"
#include <exec/memory.h>
#include <assert.h>
#include <sys/errno.h>
#include <exec/errors.h>
#include "credential.h"
struct ExecBase *SysBase;
struct DosLibrary *DOSBase;
struct Library *UtilityBase;
#ifndef UTILITY_TAGITEM_H
#include <utility/tagitem.h>
#endif
#include <proto/utility.h>
extern struct Process*owner;
static void CleanupNIO(void);
int TimeInit(void);
void TimeCleanup(void);
ASM void __UserLibCleanup(void);
/*
* Library initialization
*/
SAVEDS ASM int __UserLibInit(void)
{
SysBase = *(struct ExecBase **)4;
InitSemaphore(ni_lock);
if ((DOSBase = (void *)OpenLibrary("dos.library", 37L)) &&
(UtilityBase = OpenLibrary("utility.library", 37L)) &&
TimeInit() == 0 && LRandomInit() == 0) {
owner = (struct Process *)FindTask(NULL);
Forbid();
if (!(CredentialBase = OpenResource(CREDENTIALNAME))) {
CredentialBase = CredentialInit("root");
}
Permit();
if (CredentialBase)
return 0;
}
__UserLibCleanup();
return -1;
}
SAVEDS ASM void __UserLibCleanup(void)
{
CleanupUTMP();
CleanupNIO();
TimeCleanup();
if (DOSBase)
CloseLibrary((void *)DOSBase);
if (UtilityBase)
CloseLibrary(UtilityBase);
}
/*
* Errno handling
*/
ULONG break_mask = 0L;
int internal_errno;
void *errnop = NULL;
errnop_t errnosize;
/*
* Set errno
*/
void SetErrno(int errno)
{
internal_errno = errno;
if (errnop)
switch (errnosize) {
case es_byte:
*(UBYTE *)errnop = errno;
break;
case es_word:
*(UWORD *)errnop = errno;
break;
case es_long:
*(ULONG *)errnop = errno;
break;
}
}
/****** usergroup.library/ug_GetErr ****************************************
NAME
ug_GetErr - get current error code
SYNOPSIS
error = ug_GetErr(void)
D0
int ug_GetErr(void)
FUNCTION
Most usergroup.library functions return -1 to indicate an error.
When this happens (or whatever the defined error return for the
routine) this routine may be called to determine more information.
The default startup function will redirect the error codes also into
the global variable `errno'.
Note: there is no guarantee as to the value returned from ug_GetErr()
after a successful operation.
RESULTS
error - error code
SEE ALSO
ug_StrError(), ug_SetupContextTags(), dos.library/IoErr()
****************************************************************************
*/
/*
* Get errno
*/
SAVEDS ASM int R_ug_GetErr(void)
{
return internal_errno;
}
/*
* Handle the netinfo device
*/
struct SignalSemaphore ni_lock[1];
struct Process *owner;
static struct MsgPort *niport;
static struct NetInfoReq *nireq;
static struct Device *nidevice[2];
static APTR niunit[2];
static APTR nibuffer[2];
struct NetInfoReq *OpenNIUnit(ULONG unit)
{
/* Check ownership */
if (owner != (struct Process *)FindTask(NULL)) {
SetErrno(EDEADLK);
return NULL;
}
/* Allocate port */
if (niport == NULL) {
niport = CreateMsgPort();
if (niport == NULL)
return NULL;
}
if (nireq == NULL) {
nireq = CreateIORequest(niport, sizeof(*nireq));
if (nireq == NULL)
return NULL;
}
if (nidevice[unit]) {
/* Already opened */
nireq->io_Device = nidevice[unit];
nireq->io_Unit = niunit[unit];
} else {
if (OpenDevice(NETINFONAME, unit, (struct IORequest *)nireq, 0L)) {
return NULL;
}
nidevice[unit] = nireq->io_Device;
niunit[unit] = nireq->io_Unit;
}
if (nibuffer[unit] == NULL) {
nibuffer[unit] = AllocVec(MAXLINELEN, MEMF_PUBLIC);
if (nibuffer[unit] == NULL)
return NULL;
}
nireq->io_Length = MAXLINELEN;
nireq->io_Data = nibuffer[unit];
return nireq;
}
void CloseNIUnit(ULONG unit)
{
ObtainSemaphore(ni_lock);
if (nidevice[unit]) {
assert(nireq != NULL);
nireq->io_Device = nidevice[unit];
nireq->io_Unit = niunit[unit];
CloseDevice(nireq);
nidevice[unit] = NULL;
niunit[unit] = NULL;
}
ReleaseSemaphore(ni_lock);
}
static void CleanupNIO(void)
{
R_endpwent();
R_endgrent();
if (nibuffer[NETINFO_PASSWD_UNIT] != NULL)
FreeVec(nibuffer[NETINFO_PASSWD_UNIT]);
nibuffer[NETINFO_PASSWD_UNIT] = NULL;
if (nibuffer[NETINFO_GROUP_UNIT] != NULL)
FreeVec(nibuffer[NETINFO_GROUP_UNIT]);
nibuffer[NETINFO_GROUP_UNIT] = NULL;
if (nireq)
DeleteIORequest(nireq), nireq = NULL;
if (niport)
DeleteMsgPort(niport), niport = NULL;
}
BYTE myDoIO(struct NetInfoReq *req)
{
DoIO(req);
return req->io_Error;
}
static const BYTE ioerr2errno[-IOERR_SELFTEST] = {
/* IOERR_OPENFAIL */
ENOENT,
/* IOERR_ABORTED */
EINTR,
/* IOERR_NOCMD */
ENODEV,
/* IOERR_BADLENGTH */
EBUSY,
/* IOERR_BADADDRESS */
EFAULT,
/* IOERR_UNITBUSY */
EBUSY,
/* IOERR_SELFTEST */
ENXIO,
};
void SetDeviceErr(void)
{
short err;
if (nireq)
err = nireq->io_Error;
else
err = ENOMEM;
if (err < 0) {
if (err >= IOERR_SELFTEST)
err = ioerr2errno[-1 - err];
else
err = EIO;
}
SetErrno(err);
}
/*
* Get error string
*/
#define EUNKNOWN "Unknown error"
static const char * const __ug_errlist[] = {
"Undefined error: 0", /* 0 - ENOERROR */
"Operation not permitted", /* 1 - EPERM */
"No such entry", /* 2 - ENOENT */
"No such process", /* 3 - ESRCH */
"Interrupted library call", /* 4 - EINTR */
"Input/output error", /* 5 - EIO */
"Device not configured", /* 6 - ENXIO */
"Argument list too long", /* 7 - E2BIG */
"Exec format error", /* 8 - ENOEXEC */
"Bad file descriptor", /* 9 - EBADF */
"No child processes", /* 10 - ECHILD */
"Resource deadlock avoided", /* 11 - EDEADLK */
"Cannot allocate memory", /* 12 - ENOMEM */
"Permission denied", /* 13 - EACCES */
"Bad address", /* 14 - EFAULT */
"Block device required", /* 15 - ENOTBLK */
"Device busy", /* 16 - EBUSY */
"File exists", /* 17 - EEXIST */
"Cross-device link", /* 18 - EXDEV */
"Operation not supported by device", /* 19 - ENODEV */
"Not a directory", /* 20 - ENOTDIR */
"Is a directory", /* 21 - EISDIR */
"Invalid argument", /* 22 - EINVAL */
"Too many open files in system", /* 23 - ENFILE */
"Too many open files", /* 24 - EMFILE */
"Inappropriate operation for device", /* 25 - ENOTTY */
"Text file busy", /* 26 - ETXTBSY */
"File too large", /* 27 - EFBIG */
"No space left on device", /* 28 - ENOSPC */
"Illegal seek", /* 29 - ESPIPE */
"Read-only file system", /* 30 - EROFS */
"Too many links", /* 31 - EMLINK */
"Broken pipe", /* 32 - EPIPE */
/* math software */
"Numerical argument out of domain", /* 33 - EDOM */
"Result too large", /* 34 - ERANGE */
/* non-blocking and interrupt i/o */
"Resource temporarily unavailable", /* 35 - EAGAIN */
/* 35 - EWOULDBLOCK */
"Operation now in progress", /* 36 - EINPROGRESS */
"Operation already in progress", /* 37 - EALREADY */
/* ipc/network software -- argument errors */
"Socket operation on non-socket", /* 38 - ENOTSOCK */
"Destination address required", /* 39 - EDESTADDRREQ */
"Message too long", /* 40 - EMSGSIZE */
"Protocol wrong type for socket", /* 41 - EPROTOTYPE */
"Protocol not available", /* 42 - ENOPROTOOPT */
"Protocol not supported", /* 43 - EPROTONOSUPPORT */
"Socket type not supported", /* 44 - ESOCKTNOSUPPORT */
"Operation not supported", /* 45 - EOPNOTSUPP */
"Protocol family not supported", /* 46 - EPFNOSUPPORT */
/* 47 - EAFNOSUPPORT */
"Address family not supported by protocol family",
"Address already in use", /* 48 - EADDRINUSE */
"Can't assign requested address", /* 49 - EADDRNOTAVAIL */
/* ipc/network software -- operational errors */
"Network is down", /* 50 - ENETDOWN */
"Network is unreachable", /* 51 - ENETUNREACH */
"Network dropped connection on reset", /* 52 - ENETRESET */
"Software caused connection abort", /* 53 - ECONNABORTED */
"Connection reset by peer", /* 54 - ECONNRESET */
"No buffer space available", /* 55 - ENOBUFS */
"Socket is already connected", /* 56 - EISCONN */
"Socket is not connected", /* 57 - ENOTCONN */
"Can't send after socket shutdown", /* 58 - ESHUTDOWN */
"Too many references: can't splice", /* 59 - ETOOMANYREFS */
"Connection timed out", /* 60 - ETIMEDOUT */
"Connection refused", /* 61 - ECONNREFUSED */
"Too many levels of symbolic links", /* 62 - ELOOP */
"File name too long", /* 63 - ENAMETOOLONG */
/* should be rearranged */
"Host is down", /* 64 - EHOSTDOWN */
"No route to host", /* 65 - EHOSTUNREACH */
"Directory not empty", /* 66 - ENOTEMPTY */
};
static const int __ug_nerr = ENOTEMPTY + 1;
/****** usergroup.library/ug_StrError **************************************
NAME
ug_StrError - Return the text associated with error code
SYNOPSIS
text = ug_StrError(code)
D0 D1
const char *ug_StrError(LONG);
FUNCTION
The strerror() function maps the error number specified by the
errnum parameter to a language-dependent error message string, and
returns a pointer to the string. The string pointed to by the
return value should not be modified by the program, but may be
overwritten by a subsequent call to this function.
INPUTS
code - error code returned by ug_GetErr() function.
RESULT
text - text associated with the error code.
NOTES
The current implementation will understands also the negative IO
error codes.
BUGS
Currently only language available is English.
SEE ALSO
ug_GetErr()
******************************************************************************
*/
SAVEDS ASM const char *R_ug_StrError(REG(d1) LONG code)
{
if (code < 0) {
if (code >= IOERR_SELFTEST)
code = ioerr2errno[-1 - code];
else
code = EIO;
}
if (code >= __ug_nerr)
return EUNKNOWN;
else
return __ug_errlist[code];
}
/****** usergroup.library/ug_SetupContextTags ********************************
NAME
ug_SetupContextTagList - Set up the caller context
ug_SetupContextTags - varargs stub for ug_SetupContextTagList
SYNOPSIS
success = ug_SetupContextTagList(taglist)
D0 A1
ULONG ug_SetupContextTagList(struct TagItem *);
success = ug_SetupContextTags(...)
ULONG ug_SetupContextTags(LONG tag, ...);
FUNCTION
The function ug_SetupContextTags() will prepare the library caller
context.
INPUTS
taglist - pointer to taglist
Currently, there are defined tags as follows:
UGT_ERRNOPTR - gives the pointer to the errno variable. The error
variable is redirected to the scope of the task. If
the pointer is NULL, no redirection is done anymore.
UGT_ERRNOSIZE - specifies the size of the errno variable. Legal
values are 1, 2 and 4. The UGT_ERRNOSIZE must be
given with same call if the UGT_ERRNOPTR is given a
non-NULL value.
UGT_INTRMASK - specifies the interrupt signal mask. All blocking
library calls will be interrrupted when a signal in
the break mask is received. The signals in the
`mask' are not cleared when a library call is
interrupted. The signals in INTRMASK should be
allocated in the context of the owning task.
UGT_OWNER - changes the owner of this library instance. The
UGT_OWNET tagData must be a valid task pointer or
NULL. If the pointer is NULL, the library will have
no owner and any task can become owner by calling
ug_SetupContextTagList(UGT_OWNER, FindTask(NULL),
TAG_END) ;
Most of the library calls are allowed only for the
owner of library. Only the owner can CloseLibrary()
this library.
RESULT
If the call is successfull, value of 0 is returned. Otherwise the
value -1 is returned. Old context is cleared, if an error occurs.
The error code can be retrieved with function ug_GetErr().
ERRORS
[EINVAL] An illegal input value was specified.
BUGS
Strange and unusual things will happen if the signal allocated for
the use of the library is included in the mask.
SEE ALSO
ug_GetErr(), --background--
******************************************************************************
*/
const UBYTE *_ProgramName = USERGROUPNAME;
SAVEDS ASM int R_ug_SetupContextTagList(REG(a0) const UBYTE *name,
REG(a1) struct TagItem *tagargs)
{
struct TagItem *tag;
struct Process *caller = (struct Process *)FindTask(NULL);
if (owner != NULL && owner != caller) {
/* We should */
InMsg("ug_SetupContextTags: not an owner (%lx)", caller);
return -1;
}
if (tagargs == NULL || name == NULL) {
SetErrno(EINVAL);
return -1;
}
_ProgramName = name;
if (tag = FindTagItem(UGT_OWNER, tagargs)) {
short error;
ObtainSemaphore(ni_lock);
if (owner != NULL && owner != caller) {
if (tag->ti_Data != NULL) {
owner = (void *)tag->ti_Data;
error = 0;
} else {
error = EINVAL;
}
} else {
error = EPERM;
}
ReleaseSemaphore(ni_lock);
if (error) {
SetErrno(error);
return -1;
}
}
if (tag = FindTagItem(UGT_ERRNOLPTR, tagargs)) {
errnop = (void *)tag->ti_Data;
errnosize = es_long;
}
if (tag = FindTagItem(UGT_ERRNOWPTR, tagargs)) {
errnop = (void *)tag->ti_Data;
errnosize = es_word;
}
if (tag = FindTagItem(UGT_ERRNOBPTR, tagargs)) {
errnop = (void *)tag->ti_Data;
errnosize = es_byte;
}
if (tag = FindTagItem(UGT_INTRMASK, tagargs)) {
break_mask = tag->ti_Data;
}
return 0;
}